package cn.com.dhcc.ddi.task.service.transform.impl;

import cn.com.dhcc.app.core.exception.CompressException;
import cn.com.dhcc.app.core.exception.DaoException;
import cn.com.dhcc.app.core.exception.NiceException;
import cn.com.dhcc.app.core.exception.ServiceException;
import cn.com.dhcc.app.core.handler.compresshandler.CompressResult;
import cn.com.dhcc.app.core.handler.compresshandler.CompressService;
import cn.com.dhcc.app.core.handler.compresshandler.CompressServiceFactory;
import cn.com.dhcc.app.core.handler.compresshandler.CompressStatic;
import cn.com.dhcc.app.core.service.Log;
import cn.com.dhcc.app.core.tag.CommonStaticCode;
import cn.com.dhcc.app.core.util.JsonUtil;
import cn.com.dhcc.app.core.util.StrUtil;
import cn.com.dhcc.app.core.util.UUIDGenerator;
import cn.com.dhcc.app.pub.CM;
import cn.com.dhcc.app.pub.core.consts.DdiProperties;
import cn.com.dhcc.app.pub.core.handler.FileRecvAnalyzeHandler;
import cn.com.dhcc.app.pub.core.handler.IAnalyzeCallBack;
import cn.com.dhcc.app.pub.core.tag.staticcode.StaticCode;
import cn.com.dhcc.app.pub.core.util.filefilter.DirFilter;
import cn.com.dhcc.ddi.datamapping.dao.DataMappingDao;
import cn.com.dhcc.ddi.datamapping.dao.FuncIdentifyDao;
import cn.com.dhcc.ddi.datamapping.dao.FuncMappingDao;
import cn.com.dhcc.ddi.datamapping.vo.DataMapping;
import cn.com.dhcc.ddi.datamapping.vo.FuncIdentify;
import cn.com.dhcc.ddi.datamapping.vo.FuncMapping;
import cn.com.dhcc.ddi.datasource.dao.DataSourceDao;
import cn.com.dhcc.ddi.datasource.service.DataSourceService;
import cn.com.dhcc.ddi.datasource.vo.DataSourceVo;
import cn.com.dhcc.ddi.datasource.vo.TableColVo;
import cn.com.dhcc.ddi.datasource.vo.TableInfoVo;
import cn.com.dhcc.ddi.task.dao.TaskActiveLogDao;
import cn.com.dhcc.ddi.task.dao.TaskExecuteLogDao;
import cn.com.dhcc.ddi.task.service.ChangeVo;
import cn.com.dhcc.ddi.task.service.ChangeVo.ColPro;
import cn.com.dhcc.ddi.task.service.ChangeVo.RowPro;
import cn.com.dhcc.ddi.task.service.Result;
import cn.com.dhcc.ddi.task.service.TaskTabService;
import cn.com.dhcc.ddi.task.service.load.DataFileHandler;
import cn.com.dhcc.ddi.task.service.transform.FuncHandlerInterface;
import cn.com.dhcc.ddi.task.service.transform.FunctionAction;
import cn.com.dhcc.ddi.task.service.transform.RelatedTableVo;
import cn.com.dhcc.ddi.task.service.transform.TDataInterface;
import cn.com.dhcc.ddi.task.vo.Task;
import cn.com.dhcc.ddi.task.vo.TaskActiveLog;
import cn.com.dhcc.ddi.task.vo.TaskExecuteLog;
import org.apache.commons.collections.ListUtils;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 表到表数据映射
 *
 * @日期：2016/11/21 9:38
 * @作者：张洪涛
 * @版权所有：东华软件
 * @版本：1.0
 */
@Service
public class TDataTableExchangeImpl implements TDataInterface {
    private static Logger logger = Log.getLogger(Log.LOGTYPE.DDI);
    private static Logger trans_logger = Log.getLogger("TRANS_LOG");
    @Autowired
    private TaskExecuteLogDao taskExecuteLogDao;
    @Autowired
    private DataMappingDao dmDao;
    @Autowired
    private DataSourceDao dsDao;
    @Autowired
    private DataSourceService dataSourceService;
    @Autowired
    private TaskActiveLogDao taskActiveLogDao;
    @Autowired
    private FuncIdentifyDao funcIdentifyDao;
    @Autowired
    private FuncMappingDao funcMappingDao;
    @Autowired
    private TaskTabService taskTabService;
    /**
     * 映射数据
     *
     * @param task
     * @param taskLogId
     * @throws ServiceException
     */
    public Result transformData(Task task, String taskLogId) throws ServiceException {
        try {
            logger.info("开始执行transform...");
            Result result = new Result();
            result.setTaskLogId(taskLogId);
            //记录转换环节日志
            TaskExecuteLog transformLog = new TaskExecuteLog();
            transformLog.setId(UUIDGenerator.getUUID());
            transformLog.setTaskId(task.getId());
            transformLog.setLinkType(TaskExecuteLog.LINK_TYPE.TRANSFORM.getCode());
            transformLog.setLinkStartTime(new Date());
            transformLog.setMtime(new Date());
            transformLog.setGroupId(taskLogId);
            taskExecuteLogDao.insert(transformLog);
            result.setLinkLogId(transformLog.getId());
            //映射根目录
            String transformRoot = DdiProperties.APP_UPLOAD_FILEDATA_PATH + File.separator + "transform" + File.separator + task.getId() + File.separator + taskLogId;
            //映射文件路径
            //映射文件生成比较特殊，需要先按表生成映射后的文件，之后再将各表合并
            //映射文件目录，transform/schema/表名.xml
            String transXmlPath = transformRoot + File.separator + "mapping";
            //获取抽取日志
            TaskExecuteLog extractLog = taskExecuteLogDao.getExtractLog(taskLogId);
            if (extractLog.getLogStatus().equalsIgnoreCase(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus()) || extractLog.getLogStatus().equalsIgnoreCase("") || extractLog.getLogStatus() == null) {
                result.setStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
                result.setMsg("抽取数据失败");
                if (extractLog.getLogStatus().equalsIgnoreCase("") || extractLog.getLogStatus() == null) {
                    extractLog.setLogStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
                    extractLog.setLinkEndTime(new Date());
                    taskExecuteLogDao.update(extractLog);
                }
                return result;
            }
            if(extractLog.getTotal() == 0 ){
                String msg = "本次任务没有交换数据.";
                result.setStatus(CommonStaticCode.SUCCESSFAIL.SUCCESS.getStatus());
                result.setMsg(msg);
                transformLog.setLogStatus(CommonStaticCode.SUCCESSFAIL.SUCCESS.getStatus());
                transformLog.setLinkEndTime(new Date());
                transformLog.setLinkSummary(msg);
                transformLog.setTotal(0);
                taskExecuteLogDao.update(transformLog);
                return result;
            }
            //先复制新的文件到指定目录中，操作复制后的数据文件，防止读取文件过程中错误，导致文件失效
            String inputPath = extractLog.getLinkDataFilePath();
            if (StringUtils.isEmpty(inputPath)) {
                logger.error("获取到数据抽取文件路径失败。路径为空。");
                //如果查询出的文件目录为空，则不进行复制，只更新数据库状态，不进行后续操作
//                updateExchDataLog(exchData.getId(), StaticCode.EXCH_DATA_STATUS.WAIT.getCode());
                result.setStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
                result.setMsg("获取到数据抽取文件路径失败。路径为空。");
                return result;
            }
            String outDataPath = transformRoot + File.separator + inputPath.substring(inputPath.lastIndexOf("\\") + 1);
            File inputFile = new File(inputPath);
            File outdir = new File(transformRoot);
            if (!outdir.exists()) {
                outdir.mkdir();
            }
            File outFile = new File(outDataPath);
            logger.info("[transform]开始复制文件..." + inputPath);
            try {
                FileUtils.copyFile(inputFile, outFile);
            } catch (IOException e) {
                logger.error("[transform]copy " + inputFile + " 发生异常", e);
                result.setStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
                result.setMsg("[transform]copy " + inputFile + " 发生异常");
                return result;
            }
            logger.info("[transform]" + outFile + "文件复制完成...开始解压缩...");
            String unCompFile = unCompress(outFile, transformRoot);
            //解压失败，则状态更改为“待执行”
            if (StringUtils.isEmpty(unCompFile)) {
                logger.error("[transform]执行解压文件 失败，更改状态为\"待执行\"。");
                //删除掉复制的文件
                if (outFile.exists()) {
                    logger.error("[transform]解压文件失败，删除源文件。");
                    outFile.delete();
                }
                result.setStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
                result.setMsg("[transform]执行解压文件 失败");
                return result;
            }
            logger.info("[transform]" + outFile + "文件解压完成...解压后的文件为：" + unCompFile);
            //解压完成后，进行文件解析，并进行入库操作(根据配置的数据源信息)
            //解析抽取的数据文件并转换
            result = parseXml(task, transformLog.getId(), unCompFile, transformRoot);
            transformLog = taskExecuteLogDao.get(transformLog.getId());
            if (result.getStatus()== null || result.getStatus().equals(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus())){
                transformLog.setLogStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
                transformLog.setLogMsg("加载数据失败");
                result.setStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
                result.setMsg("加载数据失败");
            }
            transformLog.setLinkEndTime(new Date());
            taskExecuteLogDao.update(transformLog);
            return result;
        } catch (DaoException e) {
            throw new ServiceException(e);
        }
    }
    public Result createTDataFile(String transformLogId,String transformRoot,String transXmlPath) {
        Result result = new Result();
        try {
            TaskExecuteLog transformLog = taskExecuteLogDao.get( transformLogId);
            result.setLinkLogId(transformLog.getId());
            result.setTaskLogId(transformLog.getGroupId());
            Map<String,Map> relatedTables;
            //将转换前后的表名对应关系取出
            if (transformLog.getLinkSummary() != null && !transformLog.getLinkSummary().isEmpty()){
                relatedTables = JsonUtil.toMap(transformLog.getLinkSummary());
                if (!relatedTables.isEmpty()){
                    File dataXmlFile = createTDataFile(transformLog.getTaskId(), transformLog.getId(),transformRoot, transXmlPath);
                    //压缩
                    CompressResult<String> sresult = compressFile(transformRoot, dataXmlFile);
                    String absolutePath = sresult.getCommpressResultObj();
                    File afterFile = new File(absolutePath);
                    //记录映射后的数据文件路径
                    transformLog.setLinkDataFilePath(afterFile.getAbsolutePath());
                    transformLog.setLogStatus(CommonStaticCode.SUCCESSFAIL.SUCCESS.getStatus());
                    transformLog.setLinkSummary(createTransContentDetail(relatedTables,transformLog.getTaskId()));
                    transformLog.setLogMsg("数据映射成功");
                    result.setStatus(CommonStaticCode.SUCCESSFAIL.SUCCESS.getStatus());
                    result.setMsg("数据映射成功");
                }else{
                    transformLog.setLogStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
                    transformLog.setLogMsg("数据映射出错");
                    result.setStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
                    result.setMsg("数据映射出错");
                }
            }else{
                transformLog.setLogStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
                transformLog.setLogMsg("数据映射出错");
                result.setStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
                result.setMsg("数据映射出错");
            }
            taskExecuteLogDao.update(transformLog);
        } catch (Exception e) {
            trans_logger.error(e);
            result.setStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
            result.setMsg("数据映射出错");
        }

        return result;
    }

    /**
     * 生成映射详情
     * @param changeVo
     * @return
     */
    private String  createTransContentDetail( Map<String,Map> relatedTables,String taskId) throws InvocationTargetException, IntrospectionException, InstantiationException, IllegalAccessException, ServiceException {
        logger.info("进入方法createCendContentDetail().");
        StringBuilder rs = new StringBuilder();
        //将转换前后的表名对应关系取出
        int sum = 0;
        StringBuilder tables = new StringBuilder();
        for (String tablename : relatedTables.keySet()) {
            RelatedTableVo relatedTable = (RelatedTableVo) convertMap(RelatedTableVo.class, relatedTables.get(tablename));
            if (relatedTable == null) {
                continue;
            }
            sum += relatedTable.getNum();
            tables.append("表：").append(tablename).append(" -> ").append(relatedTable.getSchema()).append(".").append(relatedTable.getTableName()).append(",记录数：").append(relatedTable.getNum()).append("\r\n");
        }
        rs.append("数据映射结果,总数:").append(sum).append("\r\n").append(tables);
        logger.info("执行结束createTransContentDetail().返回值：" + rs.toString());
        return rs.toString();
    }
    /**
     * @param task
     * @param transformLog
     * @param unCompFile
     * @param sendSqlNumber
     */
    private Result parseXml(final Task task, final String transformLogId, String unCompFile, final String transformRoot)  {
        logger.info("当前线程id【" + Thread.currentThread().getId() + "-" + Thread.currentThread().getName() + "】,更新t_ddi_task_log");
        final String transXmlPath = transformRoot + File.separator + "mapping";
        final ExecutorService exec = Executors.newFixedThreadPool(DdiProperties.APP_EXECUTION_MAXQUERYNUM);
        try {
            final File uncFile = new File(unCompFile);
            DataMapping dm = dmDao.get(task.getMpId());
            final DataSourceVo destDs = dsDao.get(dm.getDestDsId());
            final TaskExecuteLog transformLog = taskExecuteLogDao.get(transformLogId);
            final TaskActiveLog log = taskActiveLogDao.getByTaskId(task.getId());

            logger.info("当前线程id【" + Thread.currentThread().getId() + "-" + Thread.currentThread().getName() + "】，获取DataSourceVo");
            logger.info("当前线程id【" + Thread.currentThread().getId() + "-" + Thread.currentThread().getName() + "】,开始解析了。。。。");
            //查询当前线程池是否有这样的线程池，按照节点名字创建
            // 开始的倒数锁
//            final CountDownLatch begin = new CountDownLatch(1);
            Runnable run = new Runnable() {
                public void run() {
                    SAXParserFactory factory = SAXParserFactory.newInstance();
                    try {
                        SAXParser parser = factory.newSAXParser();
                        parser.parse(uncFile, new DataFileHandler(FileRecvAnalyzeHandler.MAX_NUM, new IAnalyzeCallBack() {
                            @Override
                            public void proccess(ChangeVo vo) throws NiceException {
                                trans_logger.info("当前线程id【" + Thread.currentThread().getId() + "-" + Thread.currentThread().getName() + "】,vo{" + vo + "}。");
                                trans_logger.info("当前线程id【" + Thread.currentThread().getId() + "-" + Thread.currentThread().getName() + "】,transformLogId{" + transformLogId + "}。");
                                log.setMtime(new Date());
                                try {
                                    taskActiveLogDao.update(log);
                                } catch (DaoException e) {
                                    trans_logger.error("更新任务实时活动日志异常", e);
                                }
                                execute(destDs, vo, transformLogId, transXmlPath,task.getMpId());
                                if (vo.isOver()) {//如果文件解析完毕，删除该文件
                                    trans_logger.info("[parseXml]更新t_ddi_task_log表id:" + transformLogId + ",状态为：" + StaticCode.EXCH_DATA_STATUS.OVER.getCode());
                                    //更新交换日志状态信息
                                    //解析完成，通知
                                    trans_logger.info("[parseXml]回调通知修改表id:" + transformLogId + ",状态：" + CommonStaticCode.SUCCESSFAIL.SUCCESS.getStatus());
                                    boolean flag = uncFile.delete();
                                    trans_logger.warn("数据文件【" + uncFile.getAbsolutePath() + "】解析完毕，删除结果" + flag);
                                    exec.shutdown();
                                } else {
                                    trans_logger.warn("数据文件【" + uncFile.getAbsolutePath() + "】正在解析中，暂不删除");
                                }
                            }
                        }, transformLogId));
                    } catch (Exception e) {
                        trans_logger.error("解析文件异常:", e);
                        trans_logger.info("[recvTask]更新t_ddi_task_log表id:" + transformLogId + ",状态为：" + StaticCode.EXCH_DATA_STATUS.ERROR.getCode());
                        transformLog.setLogStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
                        transformLog.setLogMsg("解析文件异常");
                        try {
                            taskExecuteLogDao.update(transformLog);
                        } catch (DaoException e1) {
                            logger.error(e1);
                        }
                    }
                }
            };
            exec.submit(run);
            while (true) {
                if (exec.isTerminated()) {
                    break;
                }
                Thread.sleep(200);
            }
            return createTDataFile(transformLogId,transformRoot,transXmlPath);
        } catch (Exception e) {
            logger.error("当前线程id【" + Thread.currentThread().getId() + "-" + Thread.currentThread().getName() + "】,服务器异常:文件接收失败," + e);
        }
        return null;
    }

    /**
     * 执行sql语句
     *
     * @param listVo
     * @param changeVo
     */
    public void execute(DataSourceVo dataSourceVo, ChangeVo changeVo, String transformLogId, String transXmlPath,String mappingId) {
        logger.info("当前线程id【" + Thread.currentThread().getId() + "-" + Thread.currentThread().getName() + "】,开始解析changeVo{" + count(changeVo) + "}");

        try {
            TaskExecuteLog transformLog = taskExecuteLogDao.get(transformLogId);
            Map<String, TableInfoVo> tableMap = dataSourceService.getTableMap(dataSourceVo.getId());
            Map<String, List<ChangeVo.RowPro>> map = changeVo.getTableData();
            Map<String,RelatedTableVo> relatedTables = new HashMap<String,RelatedTableVo>();
            Map<String, Integer> transMap = convert(map, tableMap, transXmlPath,relatedTables,mappingId);
            int num = 0;
            Set<String> set = transMap.keySet();
            for (String key : set) {
                int t = transMap.get(key);
                num = num + t;
            }
            //将转换前后的表名对应关系保存到环节执行结果摘要信息中
            String linkSummary = "";
            if ( transformLog.getLinkSummary() == null || transformLog.getLinkSummary().isEmpty()){
                linkSummary = JsonUtil.toJson(relatedTables);
            }else {
                Map<String,Map> oldrelatedTables = JsonUtil.toMap(transformLog.getLinkSummary());
                Map<String,RelatedTableVo> newrelatedTables  = new HashMap<String,RelatedTableVo>();
                for (String tablename :oldrelatedTables.keySet()){
                    RelatedTableVo oldrelatedTable = (RelatedTableVo) convertMap(RelatedTableVo.class,oldrelatedTables.get(tablename));
                    newrelatedTables.put(tablename,oldrelatedTable);

                }
                for (String tablename : relatedTables.keySet()){
                    RelatedTableVo relatedTable = relatedTables.get(tablename);
                    RelatedTableVo oldrelatedTable = newrelatedTables.get(tablename);
                    if (oldrelatedTable!= null){
                        relatedTable.setNum(relatedTable.getNum() + oldrelatedTable.getNum());
                    }
                    newrelatedTables.put(tablename,relatedTable);

                }
                linkSummary = JsonUtil.toJson(newrelatedTables);
            }
            transformLog.setLinkSummary(linkSummary);
            transformLog.setTotal(transformLog.getTotal() + num);
            taskExecuteLogDao.update(transformLog);
            logger.info("当前线程id【" + Thread.currentThread().getId() + "-" + Thread.currentThread().getName() + "】,解析结束changeSqlVo，统计出来的sql共有【" + num + "】条");
            //System.err.println("当前线程【"+Thread.currentThread().getName()+"】执行结束:当前时间"+dateFormat.format(new Date()));
        } catch (Exception e) {
            logger.error("映射异常");
        }
    }

    /**
     * 将一个 Map 对象转化为一个 JavaBean
     * @param type 要转化的类型
     * @param map 包含属性值的 map
     * @return 转化出来的 JavaBean 对象
     * @throws IntrospectionException
     *             如果分析类属性失败
     * @throws IllegalAccessException
     *             如果实例化 JavaBean 失败
     * @throws InstantiationException
     *             如果实例化 JavaBean 失败
     * @throws InvocationTargetException
     *             如果调用属性的 setter 方法失败
     */
    public static Object convertMap(Class type, Map map)
            throws IntrospectionException, IllegalAccessException,
            InstantiationException, InvocationTargetException {
        BeanInfo beanInfo = Introspector.getBeanInfo(type); // 获取类属性
        Object obj = type.newInstance(); // 创建 JavaBean 对象

        // 给 JavaBean 对象的属性赋值
        PropertyDescriptor[] propertyDescriptors =  beanInfo.getPropertyDescriptors();
        for (int i = 0; i< propertyDescriptors.length; i++) {
            PropertyDescriptor descriptor = propertyDescriptors[i];
            String propertyName = descriptor.getName();

            if (map.containsKey(propertyName)) {
                // 下面一句可以 try 起来，这样当一个属性赋值失败的时候就不会影响其他属性赋值。
                Object value = map.get(propertyName);

                Object[] args = new Object[1];
                args[0] = value;

                descriptor.getWriteMethod().invoke(obj, args);
            }
        }
        return obj;
    }

    /**
     * 获取映射函数，按作用对象保存到ap
     * @param mappingId 映射id
     * @param tableName 所属表名
     * @param actTypeCode 作用对象类型
     * @return
     * @throws DaoException
     */
    private Map<String,List<FuncMapping>> getFuncMappings(String mappingId,String tableName,String actTypeCode) throws DaoException {
        Map<String,List<FuncMapping>> map = new HashMap<String, List<FuncMapping>>();
        List<String> actObjs = funcMappingDao.getFuncMappingActobjs(mappingId,tableName, actTypeCode);
        for (String actObj:actObjs) {
            List<FuncMapping> fms = funcMappingDao.getFuncMappingList(mappingId,tableName, actTypeCode,actObj);
            map.put(actObj,fms);
        }
        return map;
    }

    /**
     * 获取所有函数
     * @return
     * @throws DaoException
     */
    private Map<String,FuncIdentify> getFuncIdentifys() throws DaoException {
        Map<String,FuncIdentify> map = new HashMap<String,FuncIdentify>();
        List<FuncIdentify> funcs = funcIdentifyDao.list();
        for (FuncIdentify func: funcs ) {
            map.put(func.getId(),func);
        }
        return map;
    }

    private List<String> getArgs(String argContent){
        List<String> args = new ArrayList<String>();
        if(argContent == null || argContent.isEmpty()){
            return args;
        }
        JSONArray array = new JSONArray(argContent);
        for (int i = 0; i < array.length(); i++ ){
            String arg = array.get(i).toString();
            Map<String,String> map = new HashMap<String,String>();
            map = JsonUtil.toMap(arg);
            for (String key:map.keySet()){
                args.add(map.get(key));
            }
        }
        return args;
    }
    /**
     *
     * @Title: relaceStr
     * @Description: 去除字符串中的空格、换行符、制表符、回车
     * @param @param str
     * @param @return    参数
     * @return String    返回类型
     * @throws
     */
    public String relaceStr(String str){
        String dest = "";
        if (str != null) {
            Pattern p = Pattern.compile("\\s*|\t|\r|\n");
            Matcher m = p.matcher(str);
            dest = m.replaceAll("");
        }
        return dest;
    }

    /**
     * 排除表
     * @param fms 排除表映射集合
     * @param funcs 所有函数
     * @param tablename 表名
     * @return 如果表在排除表映射中，返回true
     * @throws ClassNotFoundException
     * @throws InvocationTargetException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private boolean removeTable(List<FuncMapping> fms,Map<String,FuncIdentify> funcs,String tablename) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException {
        for (FuncMapping fm:fms) {
            FuncIdentify func = funcs.get(fm.getFxId());
            String fxName = func.getFxNameEn();
            List<String> args = new ArrayList<String>();
            args.add(tablename);
            if (!fm.getArgContent().isEmpty()){
                List<String> argsList =  getArgs(fm.getArgContent());
                args.addAll(argsList);
            }
            FuncHandlerInterface handler = getFuncHandlerInterface(func);
            return (Boolean) handler.call(fxName, args);
        }

        return false;
    }
    private  Map<String, ColPro> addCol( List<FuncMapping> addColfms,Map<String,FuncIdentify> funcs, Map<String, ColPro> colsMap,String colName) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, DaoException {
        Map<String, ColPro> colsMapNew = new HashMap<String, ColPro>();
        for (FuncMapping addColfm:addColfms) {
            Map<String, String> argsMap = JsonUtil.toMap(addColfm.getArgContent());
            if (argsMap.get("col").equals(colName)) {
                ColPro col = colsMap.get(colName);
                FuncIdentify func = funcs.get(argsMap.get("fxId"));
                String addColValNew = col.getValue();
                if (func != null) {
                    String fxName = func.getFxNameEn();
                    List<String> args = new ArrayList<String>();
                    args.add(col.getValue());
                    if (argsMap.get("args") != null && !JSONObject.valueToString(argsMap.get("args")).isEmpty()) {
                        List<String> argsList = getArgs(argsMap.get("args"));
                        args.addAll(argsList);
                    }
                    FuncHandlerInterface handler = getFuncHandlerInterface(func);
                    addColValNew = (String) handler.call(fxName, args);
                }
                ColPro addColNew = new ColPro();
                addColNew.setName(addColfm.getActObj());
                addColNew.setValue(addColValNew);
                colsMapNew.put(addColfm.getActObj(), addColNew);
            }
        }
        return colsMapNew;
    }

    /**
     * 数据组转map
     * @param str
     * @return
     */
    private Map<String,String> arrayToMap(String str){
        Map<String,String> map = new HashMap<String, String>();
        for(String s: str.split(",")){
            map.put(s,s);
        }
        return map;
    }

    private boolean removeCol(List<FuncMapping> fms,Map<String,FuncIdentify> funcs,String tablename,String colName) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException {
        for (FuncMapping fm: fms) {
            FuncIdentify func = funcs.get(fm.getFxId());
            String fxName = func.getFxNameEn();
            String tabArr = getArg(fm.getArgContent(),func.getFxType(),"0" );
            String colStr = getArg(fm.getArgContent(),func.getFxType(),"1" );
            colStr = getArg(colStr,func.getFxType(),"0");
            Map<String,String> tabMap = arrayToMap(tabArr);
            if (tabMap.get(tablename) != null){
                if(StrUtil.isNotBank(colStr)) {
                    String[] colArr = colStr.split(",");
                    for (String col : colArr) {
                        List<String> arg = new ArrayList<String>();
                        arg.add(colName);
                        arg.add(col);
                        FuncHandlerInterface handler = getFuncHandlerInterface(func);
                        boolean flag = (Boolean) handler.call(fxName, arg);
                        if (flag) {
                           return true;
                        }
                    }
                }
            }
        }
        return false;
    }
    /**
     * 映射数据
     * @param map
     * @param tableMap
     * @param transXmlPath
     * @return
     * @throws ParseException
     * @throws NiceException
     * @throws IOException
     * @throws ServiceException
     */
    private Map<String, Integer> convert(Map<String, List<RowPro>> map, Map<String, TableInfoVo> tableMap, String transXmlPath,Map<String,RelatedTableVo> relatedTables,String mappingId) throws Exception {
        if (map != null) {
            //获取所有定义函数，用于映射
            Map<String,FuncIdentify> funcs = getFuncIdentifys();
            Set<String> tables = map.keySet();
            Map<String, Integer> tMap = new LinkedHashMap<String, Integer>();//表的对应信息

            //获取排除表映射
            List<FuncMapping> removeTablefms = funcMappingDao.getFuncMapping(mappingId, "",FunctionAction.REMOVE_TABLE, FuncMapping.ACT_TYPE.ON_TABLE.getCode());
            //获取表批量操作函数
            List<FuncMapping> bathMps = funcMappingDao.getBathFuncMps(mappingId, "", FuncMapping.ACT_TYPE.ON_TABLE.getCode());

            Map<String,String> bathTable = new HashMap<String, String>();
            for (String tablename : tables) {
                //映射后的表
                //1.表名映射
                //1.1排除表
                if (removeTable(removeTablefms,funcs,tablename)){
                  continue;
                }
                String tablenameNew = tablename;
                //1.2表名批量函数计算
                if(bathMps!= null && bathMps.size()>0){
                    for (FuncMapping fm:bathMps) {
                        FuncIdentify func = funcs.get(fm.getFxId());
                        String fxName = func.getFxNameEn();
                        String tabs = "";
                        if (!fm.getArgContent().isEmpty()){
                            String args = "";
                            JSONArray argContentArray = new JSONArray(fm.getArgContent());
                            for (int i = 0; i < argContentArray.length(); i++) {
                                String argCon = JSONObject.valueToString(argContentArray.get(i));
                                argCon = relaceStr(argCon);
                                Map<String, String> argsMap = JsonUtil.toMap(argCon);
                                if(i==0){
                                    for (String key1 : argsMap.keySet()) {
                                        tabs = argsMap.get(key1);
                                    }
                                }else{
                                    if(i==1){
                                        args += JsonUtil.toJson(argsMap);
                                    }else{
                                        args += "," + JsonUtil.toJson(argsMap);
                                    }

                                }
                            }
                            args = "["+ args +"]";
                            String[] tableArray = tabs.split(",");
                            for(String tab:tableArray){
                                if(tab.equals(tablename)){
                                    List<String> arg = new ArrayList<String>();
                                    arg.add(tablename);
                                    if (!args.isEmpty()){
                                        List<String> argsList = getArgs(args);
                                        arg.addAll(argsList);
                                    }
                                    FuncHandlerInterface handler = getFuncHandlerInterface(func);
                                    tablenameNew = (String) handler.call(fxName, arg);
                                    bathTable.put(tablename, tablenameNew);
                                }

                            }
                        }
                    }
                }
                //1.3表名计算映射
                if(bathTable.get(tablename) == null){
                    Map<String,List<FuncMapping>> tablefmsMap = getFuncMappings(mappingId,tablename, FuncMapping.ACT_TYPE.ON_TABLE.getCode());
                    List<FuncMapping> tablefms = tablefmsMap.get(tablename);
                    if(tablefms != null){
                        for (FuncMapping fm:tablefms) {
                            FuncIdentify func = funcs.get(fm.getFxId());
                            String fxName = func.getFxNameEn();
                            List<String> args = new ArrayList<String>();
                            args.add(tablename);
                            if (!fm.getArgContent().isEmpty()){
                                List<String> argsList = getArgs(fm.getArgContent());
                                args.addAll(argsList);
                            }
                            FuncHandlerInterface handler = getFuncHandlerInterface(func);
                            tablenameNew = (String) handler.call(fxName, args);
                        }
                    }
                }




                TableInfoVo table = tableMap.get(tablenameNew.toLowerCase());
                if (table == null) {
                    trans_logger.error("映射后[" + tablenameNew + "]表不存在");
                    continue;
                }
                //将映射 后的数据按表存储  schema/table.xml
                assert table != null;
                File f = createTableDataXmlFile(transXmlPath,table);
                //获取排除字段映射
//                FuncMapping removeCol = funcMappingDao.getFuncMapping(mappingId,null,FunctionAction.REMOVE_COL, FuncMapping.ACT_TYPE.ON_COLUMN.getCode());
                List<FuncMapping> bathRemoveCol = funcMappingDao.getBathMapping(mappingId, "",FunctionAction.REMOVE_COL, FuncMapping.ACT_TYPE.ON_COLUMN.getCode());
                //虚拟字段
                List<FuncMapping> addColfms = funcMappingDao.getFuncMapping(mappingId,tablename,FunctionAction.ADD_COL, FuncMapping.ACT_TYPE.ON_COLUMN.getCode());

                //获取字段表批量操作函数
                List<FuncMapping> bathColMps = funcMappingDao.getBathFuncMps(mappingId, tablename, FuncMapping.ACT_TYPE.ON_COLUMN.getCode());
                Map<String,String> bathCol= new HashMap<String, String>();
                //获取字段名计算映射
                Map<String,List<FuncMapping>> colfmsMap = getFuncMappings(mappingId,tablename, FuncMapping.ACT_TYPE.ON_COLUMN.getCode());
                //获取字段值计算映射
                Map<String,List<FuncMapping>> valfmsMap = getFuncMappings(mappingId,tablename, FuncMapping.ACT_TYPE.ON_VALUE.getCode());
                List<RowPro> list = map.get(tablename);//行对象列表
                List<RowPro> dataList = new ArrayList<RowPro>();
                for (RowPro row : list) {
                    Map<String, ColPro> colsMap = row.getColMap();//字段集合
                    String[] cols = new String[colsMap.keySet().size()];//字段集合
                    colsMap.keySet().toArray(cols);
                    Map<String, ColPro> colsMapNew = new HashMap<String, ColPro>();
                    for (String colName:cols) {
                        //2.字段名映射
                        //2.1虚拟字段
                        colsMapNew.putAll(addCol(addColfms,funcs,colsMap,colName));
                        //2.2排除字段映射
                        if(removeCol(bathRemoveCol,funcs,tablename,colName)){
                            continue;
                        }
                        String colNameNew = colName;
                        //先做批量的字段名映射，之后再做单个字段名映射
                        if(bathColMps!= null && bathColMps.size()>0){
                            for (FuncMapping fm:bathColMps) {
                                FuncIdentify func = funcs.get(fm.getFxId());
                                String fxName = func.getFxNameEn();
                                String columns = "";
                                if (!fm.getArgContent().isEmpty()){
                                    String args = "";
                                    JSONArray argContentArray = new JSONArray(fm.getArgContent());
                                    for (int i = 0; i < argContentArray.length(); i++) {
                                        String argCon = JSONObject.valueToString(argContentArray.get(i));
                                        argCon = relaceStr(argCon);
                                        Map<String, String> argsMap = JsonUtil.toMap(argCon);
                                        if(i==0){
                                            for (String key1 : argsMap.keySet()) {
                                                columns = argsMap.get(key1);
                                            }
                                        }else{
                                            if(i==1){
                                                args += JsonUtil.toJson(argsMap);
                                            }else{
                                                args += "," + JsonUtil.toJson(argsMap);
                                            }

                                        }
                                    }
                                    args = "["+ args +"]";
                                    String[] columnArray = columns.split(",");
                                    for(String column:columnArray){
                                        if(column.equals(colName)){
                                            List<String> arg = new ArrayList<String>();
                                            arg.add(colName);
                                            if (!args.isEmpty()){
                                                List<String> argsList = getArgs(args);
                                                arg.addAll(argsList);
                                            }
                                            FuncHandlerInterface handler = getFuncHandlerInterface(func);
                                            colNameNew = (String) handler.call(fxName, arg);
                                            bathCol.put(colName, colNameNew);
                                        }

                                    }
                                }
                            }
                        }
                        if(bathCol.get(colName) == null){
                            List<FuncMapping> colfms = colfmsMap.get(colName);
                            if(colfms != null) {
                                for (FuncMapping fm : colfms) {
                                    FuncIdentify func = funcs.get(fm.getFxId());
                                    String fxName = func.getFxNameEn();
                                    List<String> args = new ArrayList<String>();
                                    args.add(colName);
                                    if (!fm.getArgContent().isEmpty()) {
                                        List<String> argsList = getArgs(fm.getArgContent());
                                        args.addAll(argsList);
                                    }
                                    FuncHandlerInterface handler = getFuncHandlerInterface(func);
                                    colNameNew = (String) handler.call(fxName, args);
                                }
                            }
                        }

                        //3.字段值映射
                        ColPro col = colsMap.get(colName);
                        List<FuncMapping> colValfms = valfmsMap.get(colName);
                        String colValNew = col.getValue();
                        if(colValfms != null) {
                            for (FuncMapping fm : colValfms) {
                                FuncIdentify func = funcs.get(fm.getFxId());
                                String fxName = func.getFxNameEn();
                                List<String> args = new ArrayList<String>();
                                args.add(colValNew);
                                if (!fm.getArgContent().isEmpty()) {
                                    List<String> argsList = getArgs(fm.getArgContent());
                                    args.addAll(argsList);
                                }
                                FuncHandlerInterface handler = getFuncHandlerInterface(func);
                                colValNew = (String) handler.call(fxName, args);
                            }
                        }
                        //重新组装字段
                        ColPro colNew = new ColPro();
                        colNew.setName(colNameNew);
                        colNew.setValue(colValNew);
                        colNew.setPk(col.getPk());
                        colNew.setType(col.getType());
                        colsMapNew.put(colNameNew,colNew);
                    }
                    //将转换后的值存入Row;
                    RowPro newrow = new RowPro();
                    newrow.setColMap(colsMapNew);
                    //将转换后的值存入dataList
                    dataList.add(newrow);
                }
                if (dataList.size() > 0) {
                    ArrayList<String> datas = createXmlByData(dataList);
                    FileUtils.writeLines(f, "utf-8", datas, true);
                    tMap.put(table.getTableName(), dataList.size());
                    RelatedTableVo relatedTable = new RelatedTableVo();
                    relatedTable.setSchema(table.getSchema());
                    relatedTable.setTableName(table.getTableName());
                    relatedTable.setNum(dataList.size());
                    relatedTables.put(tablename,relatedTable);
                }
            }
            return tMap;
        }
        return null;
    }
    /**
     *
     * @Title: getArg
     * @Description: 获取参数
     * @param @param argContent
     * @param @param fxType
     * @param @param ifGetArg    1 获取参数  0获取表名或列名
     * @param @return 参数
     * @return String 返回类型
     * @throws
     */
    public String getArg(String argContent,String fxType,String ifGetArg){
        String arg = "";
        if (!argContent.isEmpty()) {
            JSONArray argContentArray = new JSONArray(argContent);
            for (int i = 0; i < argContentArray.length(); i++) {
                String argCon = JSONObject.valueToString(argContentArray.get(i));
                argCon = relaceStr(argCon);
                Map<String, String> argsMap = JsonUtil.toMap(argCon);
                if(("1").equals(ifGetArg)){
                    if(i != 0){
                        if(i==1){
                            arg += JsonUtil.toJson(argsMap);
                        }else{
                            arg += "," + JsonUtil.toJson(argsMap);
                        }
                    }
                    if(i == argContentArray.length() - 1){
                        arg = "["+ arg +"]";
                    }
                }else{
                    for (String key : argsMap.keySet()) {
                        arg += argsMap.get(key);
                    }
                    if(("3").equals(fxType) || ("5").equals(fxType)){
                        break;
                    }
                    if(i < argContentArray.length()-1){
                        arg += ",";
                    }
                }
            }
        }
        return arg;
    }

    /**
     * 解压文件
     *
     * @param needCompressFile 需要解压的文件
     * @param outPath          解压后的文件路径
     * @return true 解压成功  false 解压失败
     */
    private static String unCompress(File needCompressFile, String outPath) {
        //获取解压缩处理的service
        CompressService compressService = CompressServiceFactory.createCompressService(CompressStatic.COMPRESS_ALGORITHM.JAVA_GZIP);
        String after = null;
        try {
            String fileName = needCompressFile.getName();
            if (StringUtils.isEmpty(fileName)) {
                return null;
            }
            after = outPath + File.separator + fileName.substring(0, fileName.indexOf(".edata"));//解压缩后文件名
            after = compressService.uncompress(needCompressFile, after, true);
        } catch (CompressException e) {
            logger.error("[unCompress]解压文件发生异常", e);
        }
        return after;
    }

    /**
     * 统计
     *
     * @param changeVo
     * @return
     */
    private String count(ChangeVo changeVo) {
        Map<String, List<RowPro>> map = changeVo.getTableData();
        Set<String> keys = map != null ? map.keySet() : null;
        StringBuilder sb = new StringBuilder();
        if (keys != null && keys.size() > 0) {
            for (String string : keys) {
                sb.append("表" + string + "中的需要映射的数据【" + map.get(string).size() + "】---");
            }
        }
        return sb.toString();
    }

    /**
     * 转换后的数据存储
     *
     * @param datasList
     * @return
     * @throws NiceException
     * @throws ParseException
     */
    private ArrayList<String> createXmlByData(
            List<RowPro> datasList) throws NiceException, ParseException {
        logger.info("进入方法createXmlByData()。");
        ArrayList<String> arrayList = new ArrayList<String>();
        for (RowPro row : datasList) {
            //以前同步过，但是时间错字段被修改了。这个时候不抽取insert，而是抽取update
            String rowData = createXmlBySingleRow(row);
            if (StrUtil.isNotBank(rowData)) {
                arrayList.add("<row>" + rowData + "</row>");
            }

        }
        logger.info("执行结束createXmlByData()。");
        return arrayList;
    }

    /**
     * 行数据存储
     *
     * @param row
     * @return 行数l
     * @throws NiceException
     * @throws ParseException
     */
    private String createXmlBySingleRow(RowPro row) throws NiceException, ParseException {
        logger.info("进入方法createInsertXmlBySingleRow()。");
        StringBuilder insertXml = new StringBuilder();
        //特殊情况，如果任务配置了修改和删除，但是此时修改了上次同步记录的时间戳字段为大于上次同步时间，此时抽取出insert语句，就会出现违反唯一性约束的问题。
        //解决办法为：在此条件下，不抽取此条pk对应记录的insert语句，让update去做
        Map<String, ColPro> colsMap = row.getColMap();//字段集合
        String[] cols = new String[colsMap.size()];
        colsMap.keySet().toArray(cols);
        for (String colName : cols) {
            ColPro col = colsMap.get(colName);
            insertXml.append("<col colName='").append(col.getName()).append("' colType='").append(col.getType()).append("' isPK='").append(col.getPk()).append("'>");
            insertXml.append("<![CDATA[").append(col.getValue()).append("]]>");
            insertXml.append("</col>");
        }
        logger.info("[createXmlBySingleRow]Return xml:" + insertXml.toString());
        return insertXml.toString();
    }


    /**
     * 压缩文件
     *
     * @param uploadRoot
     * @param before
     * @return
     * @throws ServiceException
     */
    private CompressResult<String> compressFile(String uploadRoot, File before) throws ServiceException {
        try {
            CompressService compressService = CompressServiceFactory.createCompressService(CompressStatic.COMPRESS_ALGORITHM.JAVA_GZIP);
            String after = uploadRoot + File.separator + before.getName() + ".tdata";//压缩后文件名
            CompressResult<String> sresult = compressService.compress(before, after, true);
            logger.info("压缩文件成功:" + sresult.getCommpressResultObj());
            return sresult;
        } catch (Exception e1) {
            logger.error("压缩文件" + before + "发生异常", e1);
            throw new ServiceException("压缩文件" + before + "发生异常", e1);
        }
    }

    /**
     * 生成单表映射文件
     *
     * @param xmlpath
     * @return
     * @throws ServiceException
     */
    private File createTableDataXmlFile(String xmlpath , TableInfoVo table) throws ServiceException {
        File formateFolder = new File(xmlpath + File.separator + table.getSchema());
        if (!formateFolder.exists()) {
            logger.info(formateFolder + "目录不存在，创建。");
            formateFolder.mkdirs();
        }
        String dataXmlPath = xmlpath  + File.separator + table.getSchema() + File.separator + table.getTableName() + ".xml";
        File dataXmlFile = new File(dataXmlPath);
        if (!dataXmlFile.exists()) {
            try {
                logger.info(dataXmlFile + "不存在，创建新文件。");
                dataXmlFile.createNewFile();
            } catch (IOException e) {
                logger.error("创建文件" + dataXmlFile + "发生异常：", e);
                throw new ServiceException(e);
            }
        }
        return dataXmlFile;
    }

    /**
     * 合并表数据文件，生成映射数据文件
     *
     * @param taskId
     * @param root
     * @param tableFileRoot
     * @return
     * @throws IOException
     * @throws DaoException
     */
    private File createTDataFile(String taskId,String transformLogId, String root, String tableFileRoot) throws IOException, DaoException, ServiceException, InvocationTargetException, IntrospectionException, InstantiationException, IllegalAccessException {
        File dir = new File(tableFileRoot);
        File dataFile = null;
        List<TableInfoVo> tasksTables = taskTabService.getListBytaskId(taskId);
        TaskExecuteLog transformLog = taskExecuteLogDao.get(transformLogId);
        //将转换前后的表名对应关系取出
        Map<String,Map> relatedTables = JsonUtil.toMap(transformLog.getLinkSummary());
        dataFile = createDataXmlFile(root);
        FileUtils.writeStringToFile(dataFile, "<data>\r\n", "utf-8", true);
        tasksTables = sortTableByFk(tasksTables);
        for (TableInfoVo tableInfo : tasksTables) {
            if (relatedTables.get(tableInfo.getTableName()) != null && !relatedTables.get(tableInfo.getTableName()).isEmpty()){
                RelatedTableVo relatedTable = (RelatedTableVo) convertMap(RelatedTableVo.class,relatedTables.get(tableInfo.getTableName()));
                if (relatedTable == null){
                    continue;
                }
                String schema = relatedTable.getSchema();
                String tableName = relatedTable.getTableName();
                String tableFilePath = tableFileRoot + File.separator + schema + File.separator + tableName + ".xml";
                File tableFile = new File(tableFilePath);
                if (tableFile.exists()) {
                    trans_logger.error("合并映射数据：表[" + schema + "." + tableName + "]");
                    FileUtils.writeStringToFile(dataFile, "<table name='" + schema+ "." + tableName + "'>\r\n", "utf-8", true);
                    FileUtils.copyFile(tableFile, FileUtils.openOutputStream(dataFile, true));
                    FileUtils.writeStringToFile(dataFile, "</table>\r\n", "utf-8", true);
                    tableFile.getAbsoluteFile().delete();
                }
            }
        }
        FileUtils.writeStringToFile(dataFile, "</data>", "utf-8", true);
        return dataFile;
    }

    /**
     * 根据外键关系排序
     *
     * @param tasksTables
     * @return
     */
    private List<TableInfoVo> sortTableByFk(
            List<TableInfoVo> tasksTables) {
        logger.info("进入方法sortTableByFk()。");
        if (tasksTables == null || tasksTables.isEmpty()) {
            return tasksTables;
        }
        List<TableInfoVo> newList = new ArrayList<TableInfoVo>();
        for (TableInfoVo taskTab : tasksTables) {
            if (getTables(tasksTables, taskTab).isEmpty() && !newList.contains(taskTab)) {
                newList.add(taskTab);
            }
        }

        for (TableInfoVo taskTab : newList) {
            if (newList.contains(taskTab)) {
                tasksTables.remove(taskTab);
            }
        }
        sortTab(tasksTables, newList);
        logger.info("执行完毕sortTableByFk()。");
        return newList;
    }

    /**
     * 排序
     *
     * @param tasksTables 有主键的列表
     * @param newList     排序的列表
     * @return
     */
    @SuppressWarnings("unchecked")
    private List<TableInfoVo> sortTab(List<TableInfoVo> tasksTables, List<TableInfoVo> newList) {
        if (tasksTables == null || tasksTables.isEmpty()) {
            return newList;
        }
        while (tasksTables.size() > 0) {
            if (tasksTables.size() == 1) {
                newList.add(tasksTables.get(0));
            } else if (tasksTables.size() > 1) {
                callback(tasksTables, tasksTables.get(0), newList);
            }
            tasksTables = ListUtils.subtract(tasksTables, newList);
        }
        return newList;
    }

    /**
     * 回调函数，取出没有外键的表，放入到newList中去
     *
     * @param tasksTables
     * @param taskTab
     * @param newList
     */
    public void callback(List<TableInfoVo> tasksTables, TableInfoVo taskTab, List<TableInfoVo> newList) {
        List<TableInfoVo> tabs = getTables(tasksTables, taskTab);
        if (tabs.isEmpty() && !newList.contains(taskTab)) {
            newList.add(taskTab);
        } else {
            for (TableInfoVo tab : tabs) {
                callback(tasksTables, tab, newList);
                break;
            }
        }
    }

    /**
     * 从tasksTables集合中，找出tab表外键关联的表的集合
     *
     * @param tasksTables
     * @param tab
     * @return
     */
    private List<TableInfoVo> getTables(List<TableInfoVo> tasksTables, TableInfoVo tab) {
        List<TableInfoVo> tabs = new ArrayList<TableInfoVo>();
        List<TableColVo> cols = tab.getTableColVos();
        for (TableColVo taskTabCol : cols) {
            if (taskTabCol.getFkTableName() != null && !"".equals(taskTabCol.getFkTableName())) {//某个表的外键表
                TableInfoVo tab1 = getTable(tasksTables, taskTabCol);
                if (tasksTables.contains(tab1)) {
                    tabs.add(tab1);
                }
            }
        }
        return tabs;
    }

    /**
     * 获取外建表
     *
     * @param tasksTables
     * @param pkCol
     * @return
     */
    private TableInfoVo getTable(List<TableInfoVo> tasksTables, TableColVo pkCol) {
        for (TableInfoVo taskTab : tasksTables) {
            if (pkCol.getFkTableName().equals(taskTab.getTableName())) {
                return taskTab;
            }
        }
        return null;
    }

    /**
     * 生成数据文件
     *
     * @param uploadRoot
     * @return
     * @throws ServiceException
     */
    private File createDataXmlFile(String uploadRoot) throws IOException {
        File uploadFolder = new File(uploadRoot);
        if (!uploadFolder.exists()) {
            logger.info(uploadFolder + "目录不存在，创建。");
            uploadFolder.mkdirs();
        }
        String dataXmlPath = uploadRoot + File.separator + UUIDGenerator.getUUID() + ".xml";
        File dataXmlFile = new File(dataXmlPath);
        if (!dataXmlFile.exists()) {
            dataXmlFile.createNewFile();
        }
        return dataXmlFile;
    }

    /**
     * 获取目录下文件
     *
     * @param files
     * @param list
     * @param filefilter
     * @param type
     * @param flag
     */
    public static void method(File[] files, List<File> list,
                              FilenameFilter filefilter, String type, boolean flag) {
        if (files != null) {
            if (flag) {
                for (File f : files) {
                    if (f.isDirectory())
                        method(f.listFiles(filefilter), list, filefilter, type, flag);
                    else if (DirFilter.match(type, f.getName())) {
                        list.add(f);
                    }
                }
            } else {
                for (File f : files) {
                    if (DirFilter.match(type, f.getName())) {
                        list.add(f);
                    }
                }
            }
        }
    }

    /**
     * 获取函数处理类
     *
     * @param func
     * @return
     */
    private FuncHandlerInterface getFuncHandlerInterface(FuncIdentify func) {
        return CM.getBean(FuncIdentify.FUNC_TYPE.find(func.getIsCustomized()).getHandler());
    }
}
